excel导出文本格式设置为数值(easypoi)

场景

导出的数值单元格格式是文本。 客户每次都要手动转为数值,往往一个表格就是好多万数据,转换起来等半天。

解决方案

听说@Excel 设置type=10即可。 实测无效。

设置type=10对不对

这样设置是对的。 但是为什么没有效果呢?
仔细跟代码,发现type=10,会设置单元格的type为 Cell.CELL_TYPE_NUMERIC 。 单元格的值属于CellValue ,和CelType都是属于Cell 。
但是单元格属性 属于 CellStyle。
所以虽然值的输出符合规范了,但是单元格显示还是为文本。

导出用到的主要元素和依赖关系

使用easypoi 导出excel只用简单的一个方法。
ExcelExportUtil.exportExcel(params, StatisticEntity.class, list);
主要元素列表如下:

名称描述
ExportParams定义导出的文件名,中文名,文件类型,导出样式等。
ExcelExportStatisticStyler继承自ExcelExportStylerDefaultImpl类,定义样式。
通过params.setStyle(ExcelExportStatisticStyler.class); 设置到ExportParams中。
如果不指定,默认使用ExcelExportStylerDefaultImpl
StatisticEntity导出单元格的实体,这里可以设置数据规则
List<StatisticEntity> list = new ArrayList<StatisticEntity>(); // TODO list中添加数据根据情况自己写
ExportParams params = new ExportParams("2412312", "测试", ExcelType.XSSF);
params.setStyle(ExcelExportStatisticStyler.class);
Workbook workbook = ExcelExportUtil.exportExcel(params, StatisticEntity.class, list);

打造属于自己的styler

好的,既然ExportParams 可以setStyle,那么我们写个类,继承ExcelExportStylerDefaultImpl 重写 getStyles方法不就成了么。

错误的写法

思路,依照最小改动原则,先获取已有的style,然后添加type=10的处理逻辑。代码:

@Override
public CellStyle getStyles2(boolean noneStyler, ExcelExportEntity entity) {
    CellStyle styles = super.getStyles(noneStyler, entity); // 获取style
    // type=10 的处理
    if (entity != null && 10==entity.getType()) {
        styles.setDataFormat((short) BuiltinFormats.getBuiltinFormat("0.00"));
        return styles;
    }
    return styles;
}

测了下发现报错, 是因为子类重写getStyles()方法,super.getStyles()调的就是子类的getStyles()方法。 这不无限循环了么。

重新写逻辑

代码:

@Override
public CellStyle getStyles(boolean noneStyler, ExcelExportEntity entity) {
    if (entity != null
        && 10==entity.getType()) {
        return numberCellStyle;
    }
    return super.getStyles(noneStyler, entity);
}

实测成功。
导出的excel单元格格式为 自定义 0.00 。这还不是客户要求的数值格式。但是只能做到这了。
至少我目前没找到如何设置为数值格式。

ExcelExportStatisticStyler 类完整的代码
public class ExcelExportStatisticStyler extends ExcelExportStylerDefaultImpl {

    private CellStyle numberCellStyle;

    public ExcelExportStatisticStyler(Workbook workbook) {
        super(workbook);
        createNumberCellStyler();
    }

    private void createNumberCellStyler() {
        numberCellStyle = workbook.createCellStyle();
        numberCellStyle.setAlignment(HorizontalAlignment.CENTER);
        numberCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        numberCellStyle.setDataFormat((short) BuiltinFormats.getBuiltinFormat("0.00"));
        numberCellStyle.setWrapText(true);
    }

    @Override
    public CellStyle getStyles(boolean noneStyler, ExcelExportEntity entity) {
        if (entity != null
            && 10==entity.getType()) {
            return numberCellStyle;
        }
        return super.getStyles(noneStyler, entity);
    }
}

setDataFormat有2种方式入参形式

1、字符串格式(推荐,可读性更强)
2、_formats 数组的下标

两种方式,本质上没区别, 传入string也是根据字面值,找_formats对应的下标。
见BuiltinFormats源码 (强调 - 自定义格式一定要在_formats 数组内,否则无效):

public static int getBuiltinFormat(String pFmt) {
	String fmt = "TEXT".equalsIgnoreCase(pFmt) ? "@" : pFmt;

	int i = -1;
	for (String f : _formats) {
	    i++;
	    if (f.equals(fmt)) {
	        return i; 
	    }
	}
	
	return -1;
}

两种设置的例子:

// 使用字符串定义格式
cellStyle.setDataFormat((short) BuiltinFormats.getBuiltinFormat("0.00"));
// BuiltinFormats._formats 数组中的下标
cellStyle.setDataFormat((short) 1); 

解决总结

步骤:
@Excel 中添加 type=10
写个类继承ExcelExportStylerDefaultImpl ,重写getStyles()方法
导出前ExportParams。

既然重写了getStyles(),那么其实type=10并不是唯一的办法。
官网就是根据name中是否包含int,double等类型来判断的,当然@Excel中的name要记得配合。(感觉type=10比改name更方便,更解耦)

setAlignment(HorizontalAlignment.CENTER) 报错

版本的问题。 报错代码如下:

numberCellStyle.setAlignment(HorizontalAlignment.CENTER);
numberCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

调整为如下代码即可:

numberCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
numberCellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

debug跟代码一行一行看

ExcelExportBase类中的createCells方法中,如果类型为double,则进入如下逻辑:

else if (entity.getType() == BaseEntityTypeConstants.DoubleType) {
}

ExcelExportBase类中的createDoubleCell方法(type=10时设置了cellType):

public void createDoubleCell(Row row, int index, String text, CellStyle style,ExcelExportEntity entity) {
    Cell cell = row.createCell(index);
    if (text != null && text.length() > 0) {
        cell.setCellValue(Double.parseDouble(text));
    } else {
        cell.setCellValue(-1);
    }
    cell.setCellType(Cell.CELL_TYPE_NUMERIC); // 这里是设置了celltype为0,表示数字格式
    if (style != null) {  // 这里设置style
        cell.setCellStyle(style);
    }
    addStatisticsData(index, text, entity);
}

是不是type不影响页面excel的文本格式,而是由style控制的呢。

easypoi支持的自定义格式列表

BuiltinFormats类的_formats列表里的自定义格式才有效,否则就会使用文本格式。

private final static String[] _formats = {
        "General",
        "0",
        "0.00",
        "#,##0",
        "#,##0.00",
        "\"$\"#,##0_);(\"$\"#,##0)",
        "\"$\"#,##0_);[Red](\"$\"#,##0)",
        "\"$\"#,##0.00_);(\"$\"#,##0.00)",
        "\"$\"#,##0.00_);[Red](\"$\"#,##0.00)",
        "0%",
        "0.00%",
        "0.00E+00",
        "# ?/?",
        "# ??/??",
        "m/d/yy",
        "d-mmm-yy",
        "d-mmm",
        "mmm-yy",
        "h:mm AM/PM",
        "h:mm:ss AM/PM",
        "h:mm",
        "h:mm:ss",
        "m/d/yy h:mm",

        // 0x17 - 0x24 reserved for international and undocumented
        // TODO - one junit relies on these values which seems incorrect
        "reserved-0x17",
        "reserved-0x18",
        "reserved-0x19",
        "reserved-0x1A",
        "reserved-0x1B",
        "reserved-0x1C",
        "reserved-0x1D",
        "reserved-0x1E",
        "reserved-0x1F",
        "reserved-0x20",
        "reserved-0x21",
        "reserved-0x22",
        "reserved-0x23",
        "reserved-0x24",
        
        "#,##0_);(#,##0)",
        "#,##0_);[Red](#,##0)",
        "#,##0.00_);(#,##0.00)",
        "#,##0.00_);[Red](#,##0.00)",
		"_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
        "_(\"$\"* #,##0_);_(\"$\"* (#,##0);_(\"$\"* \"-\"_);_(@_)",
        "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
        "_(\"$\"* #,##0.00_);_(\"$\"* (#,##0.00);_(\"$\"* \"-\"??_);_(@_)",
        "mm:ss",
        "[h]:mm:ss",
        "mm:ss.0",
        "##0.0E+0",
        "@"
	};
  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Easypoi是一个基于Spring Boot框架的开源项目,主要用于企业级的数据导出功能,支持将数据转换成Excel、Word等格式文件。对于日期格式的处理,Easypoi提供了多种方式来满足各种需求。 当你使用Easypoi导出Excel时,关于日期格式的设置有以下几种情况: 1. **自动识别并适配**:默认情况下,Easypoi能够智能地判断日期的格式,并尝试适应Excel中的相应日期样式。例如,如果你在数据库中存储的是`yyyy-MM-dd`格式的日期字符串,在导出时可能会自动生成类似于`dd月yy日`这样的日期显示方式。 2. **手动指定格式**:你可以通过配置来显式地指定日期在Excel中的格式。这通常涉及到两个步骤:一是从数据库获取日期数据;二是使用特定的日期格式字符串来控制输出。 - **获取日期数据**:首先,你需要从数据库中检索到需要导出的日期数据,通常是某个字段包含日期信息。 - **应用日期格式**:然后使用Easypoi提供的API来转换这个日期值。这通常包括两个关键部分:获取日期值以及将其转换为Excel所接受的格式字符串。例如,可以使用如下的格式字符串:“yyyy-MM-dd”来表示日期。 3. **兼容特殊日期格式**:如果日期格式非常特定,比如“yyyyMMdd”或者包含了额外的时间信息,则需要通过相应的日期解析和格式化工具(如Java的`SimpleDateFormat`类)来处理。这一步骤需要明确理解日期的原始格式和预期在Excel中的显示形式。 4. **错误处理**:有时,由于日期时间的输入不规范或是其他原因,可能出现无法正常识别或转换的情况。在使用Easypoi时,应考虑添加适当的异常处理机制,以便于在遇到无效日期格式时给出清晰的错误提示或者采取备选策略。 总之,Easypoi为开发者提供了一种便捷的方式来生成Excel文件,特别是针对日期格式的处理。合理利用其内置的功能和灵活性,结合必要的自定义配置,可以轻松地适应各种复杂的日期格式需求。当然,具体的实现细节会依赖于你的业务场景和数据的具体格式。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值